package chatclient.applets.components;


import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import javax.swing.JComponent;

public class Scrollbar extends JComponent
        implements Adjustable, ActionListener, MouseListener, MouseMotionListener {

    
    private final Object sync;
    private Vector listeners;
    private Vector newListeners;
    private int listenersLocks;
    private Button decrementButton;
    private Button incrementButton;
    private Image bar;
    private Image thumb;
    private Image thumbTop;
    private Image thumbBottom;
    private boolean dragging;
    private int dragOffset;
    private int orientation;
    private int value;
    private int minimum;
    private int maximum;
    private int visible;
    private int unitIncrement;
    private int blockIncrement;    
    
    public Scrollbar(int i, int j, int k, int l, int i1, Image image, Image image1,
            Image image2, Image image3, Button button, Button button1) {
        orientation = i;
        bar = image;
        thumb = image1;
        thumbTop = image2;
        thumbBottom = image3;
        decrementButton = button;
        incrementButton = button1;
        sync = new Object();
        setValues(j, k, l, i1);
        listeners = new Vector();
        addMouseListener(this);
        addMouseMotionListener(this);
        button.addActionListener(this);
        button1.addActionListener(this);
        setLayout(new BorderLayout());
        add(button, "North");
        add(button1, "South");
    }

    public void destroy() {
        setVisible(false);
        removeMouseListener(this);
        decrementButton.removeActionListener(this);
        incrementButton.removeActionListener(this);
        listeners.removeAllElements();
        newListeners.removeAllElements();
    }

    public boolean isDestroyed() {
        return !isVisible();
    }

    private void lockListeners(boolean flag) {
        synchronized (listeners) {
            listenersLocks++;
            if (flag && newListeners == null) {
                newListeners = (Vector) listeners.clone();
            }
        }
    }

    private void unlockListeners() {
        synchronized (listeners) {
            if (--listenersLocks == 0 && newListeners != null) {
                listeners = newListeners;
            }
        }
    }

    @Override
    public void addAdjustmentListener(AdjustmentListener adjustmentlistener) {
        lockListeners(true);
        if (!newListeners.contains(adjustmentlistener)) {
            newListeners.addElement(adjustmentlistener);
        }
        unlockListeners();
    }

    @Override
    public void removeAdjustmentListener(AdjustmentListener adjustmentlistener) {
        lockListeners(true);
        newListeners.removeElement(adjustmentlistener);
        unlockListeners();
    }

    public void notifyAdjustmentListeners(int i, int j) {
        AdjustmentEvent adjustmentevent = new AdjustmentEvent(this, 601, i, j);
        lockListeners(false);
        for (int k = 0; k < listeners.size(); k++) {
            ((AdjustmentListener) listeners.elementAt(k)).adjustmentValueChanged(adjustmentevent);
        }

        unlockListeners();
    }

    @Override
    public int getOrientation() {
        return orientation;
    }

    public void setOrientation(int i) {
        orientation = i;
    }

    @Override
    public int getValue() {
        return value;
    }

    @Override
    public void setValue(int i) {
        synchronized (sync) {
            _setValues(i, visible, minimum, maximum);
        }
    }

    public int _setValue(int i) {
        int j;
        synchronized (sync) {
            _setValues(i, visible, minimum, maximum);
            j = value;
        }
        return j;
    }

    public int _changeValue(int i) {
        int j;
        synchronized (sync) {
            _setValues(value + i, visible, minimum, maximum);
            j = value;
        }
        return j;
    }

    @Override
    public int getMinimum() {
        return minimum;
    }

    @Override
    public void setMinimum(int i) {
        synchronized (sync) {
            _setValues(value, visible, i, maximum);
        }
    }

    @Override
    public int getMaximum() {
        return maximum;
    }

    @Override
    public void setMaximum(int i) {
        synchronized (sync) {
            _setValues(value, visible, minimum, i);
        }
    }

    @Override
    public int getVisibleAmount() {
        return visible;
    }

    @Override
    public void setVisibleAmount(int i) {
        synchronized (sync) {
            _setValues(value, i, minimum, maximum);
        }
    }

    public void setValues(int i, int j, int k, int l) {
        synchronized (sync) {
            _setValues(i, j, k, l);
        }
    }

    private void _setValues(int i, int j, int k, int l) {
        minimum = k;
        maximum = l;
        maximum = checkRange(l, minimum, maximum);
        visible = checkRange(j, 0, maximum - minimum);
        value = checkRange(i, minimum, maximum - visible);
        repaint();
    }

    private int checkRange(int i, int j, int k) {
        i = Math.max(i, j);
        i = Math.min(i, k);
        return i;
    }

    @Override
    public int getUnitIncrement() {
        return unitIncrement;
    }

    @Override
    public void setUnitIncrement(int i) {
        synchronized (sync) {
            unitIncrement = i;
        }
    }

    @Override
    public int getBlockIncrement() {
        return blockIncrement;
    }

    @Override
    public void setBlockIncrement(int i) {
        synchronized (sync) {
            blockIncrement = i;
        }
    }

    @Override
    public void actionPerformed(ActionEvent actionevent) {
        Object obj = actionevent.getSource();
        if (obj == decrementButton) {
            int i = _changeValue(-unitIncrement);
            notifyAdjustmentListeners(2, i);
        } else if (obj == incrementButton) {
            int j = _changeValue(unitIncrement);
            notifyAdjustmentListeners(1, j);
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        
        super.paintComponent(g);
        
        paintBar(g, size().height);
    }

    public void paintBar(Graphics g, int i) {
        int j = 0;
        int k = 0;
        int l = 0;
        int i1 = 0;
        if (bar != null) {
            j = Math.max(0, bar.getHeight(this));
        }
        if (thumb != null) {
            k = Math.max(0, thumb.getHeight(this));
        }
        if (thumbTop != null) {
            l = Math.max(0, thumbTop.getHeight(this));
        }
        if (thumbBottom != null) {
            i1 = Math.max(0, thumbBottom.getHeight(this));
        }
        synchronized (sync) {
            float f = (float) i / (float) (maximum - minimum);
            int i2 = (int) (f * (float) (value - minimum));
            int j2 = (int) (f * (float) ((value + visible) - minimum));
            if (j > 0) {
                for (int j1 = 0; j1 < i2; j1 += j) {
                    g.drawImage(bar, 0, j1, this);
                }

                for (int k1 = j2; k1 < i; k1 += j) {
                    g.drawImage(bar, 0, k1, this);
                }

            }
            if (k > 0) {
                for (int l1 = i2 + l; l1 < j2 - i1; l1 += k) {
                    g.drawImage(thumb, 0, l1, this);
                }

            }
            if (l > 0) {
                g.drawImage(thumbTop, 0, i2, this);
            }
            if (i1 > 0) {
                g.drawImage(thumbBottom, 0, j2 - i1, this);
            }
        }
    }

    @Override
    public void mouseClicked(MouseEvent mouseevent1) {
    }

    @Override
    public void mouseEntered(MouseEvent mouseevent1) {
    }

    @Override
    public void mouseExited(MouseEvent mouseevent1) {
    }

    @Override
    public void mousePressed(MouseEvent mouseevent) {
        if (mouseevent.getSource() != this) {
            return;
        }
        int i = valueFromPosition(mouseevent.getY(), size().height);
        if (i < value) {
            int j = _changeValue(-blockIncrement);
            notifyAdjustmentListeners(3, j);
        } else if (i > value + visible) {
            int k = _changeValue(blockIncrement);
            notifyAdjustmentListeners(4, k);
        } else {
            dragging = true;
            dragOffset = i - value;
        }
    }

    @Override
    public void mouseReleased(MouseEvent mouseevent) {
        if (mouseevent.getSource() != this) {
            return;
        } else {
            dragging = false;
            return;
        }
    }

    @Override
    public void mouseDragged(MouseEvent mouseevent) {
        if (mouseevent.getSource() != this || !dragging) {
            return;
        } else {
            int i = valueFromPosition(mouseevent.getY(), size().height);
            int j = _setValue(i - dragOffset);
            notifyAdjustmentListeners(5, j);
            return;
        }
    }

    @Override
    public void mouseMoved(MouseEvent mouseevent1) {
    }

    private int valueFromPosition(int i, int j) {
        return minimum + (int) ((float) (maximum - minimum) * ((float) i / (float) j));
    }

}
